/*
 * @Description:堆叠转组合柱状图
 * @Author: YoungWind
 * @Date: 2020-09-27 14:51:14
 * @LastEditTime: 2020-09-28 02:03:11
 * @LastEditors: YoungWind
 * @FilePath: \ccd3\src\ccd3\bar\charts\StackedToGroupedBar.js
 */

import BaseChart from '../../BaseChart.js'

export default class StackedToGroupedBar extends BaseChart {
  constructor(id, data) {
    super(id, data)

    this.groupKey = 'x';
    this.filterKeys = [];
    this.yAxisTitle = 'title';

    this.xAxis = null;
    //根据groupKey先进行第一层分组
    this.xAxisScale = null;
    this.xAxisGroup = null;
    //根据keys再进行第二层分组
    this.xKeysAxisScale = null;

    //堆叠Y轴比例尺
    this.yStackedAxis = null;
    this.yStackedAxisScale = null;
    this.yAxisGroup = null;

    //分组Y轴比例尺
    this.yGroupedAxis = null;
    this.yGroupedAxisScale = null;
    this.yGroupedAxisGroup = null;

    this.rects = null;
    this.legend = null;
    this.legendGroup = null;
    this.color = d3.interpolateBlues;
  }

  /**
   * @description: 设置X轴字段
   * @param {type} 
   * @return {type} 
   */
  setGroupKey(name) {
    this.groupKey = name;
    return this;
  }

  /**
   * @description: 设置需要过滤的字段
   * @param {type} 
   * @return {type} 
   */
  setFilterKeys(arr) {
    this.filterKeys = arr;
    return this;
  }

  /**
   * @description: 设置y轴标题
   * @param {type} 
   * @return {type} 
   */
  setYAxisTitle(title) {
    this.yAxisTitle = title;
    return this;
  }

  /**
   * @description: 初始化
   * @param {type} 
   * @return {type} 
   */
  init() {
    this.initSvg();
    this.initMainGroup();
    this.initAxes();
    this.initRects();
    return this;
  }

  /**
   * @description: 初始化坐标轴
   * @param {type} 
   * @return {type} 
   */
  initAxes() {
    this.xAxisGroup = this.svg.append('g')
      .attr('id', `${this.id}xAxis`)
      .attr('transform', `translate(${this.margin.left},${this.margin.top + this.innerHeight})`);

    this.yAxisGroup = this.svg.append('g')
      .attr('id', `${this.id}yStackedAxis`)
      .attr('transform', `translate(${this.margin.left},${this.margin.top})`);
  }

  /**
   * @description: 初始化柱状图
   * @param {type} 
   * @return {type} 
   */
  initRects() {
    this.rectsGroup = this.mg.append('g')
      .attr('id', `${this.id}rectsGroup`)
  }

  /**
   * @description: 渲染视图
   * @param {type} 
   * @return {type} 
   */
  render(data) {
    if (data) {
      this.data = data;
    }
    this.renderData();
    this.renderScale();
    this.renderXAxes();
    this.renderYStackedAxes();
    this.renderRects();
    return this;
  }

  /**
   * @description: 处理更新后的数据
   * @param {type} 
   * @return {type} 
   */
  renderData() {
    //过滤数据
    this.keys = this.data.columns.filter(d => !this.filterKeys.includes(d) && d !== this.groupKey);
    this.series = d3.stack()
      .keys(this.keys)(this.data)
      .map((d, i) => (d.forEach(v => {
        v.key = d.key;
        v.index = i
      }), d))
    // .map((d, i) => d.map(([y0, y1]) => {
    //   return [y0, y1, i, d.key]
    // }))
    // this.series = d3.stack()
    //   .keys(this.keys)
    //   (this.data) // stacked yz
    //   .map((data, i) => data.map(([y0, y1]) => [y0, y1, i]))

    console.log(this.series);
  }

  /**
   * @description: 更新坐标轴比例尺
   * @param {type} 
   * @return {type} 
   */
  renderScale() {
    this.xAxisScale = d3.scaleBand()
      .domain(this.data.map(d => d[this.groupKey]))
      .rangeRound([0, this.innerWidth])
      .paddingInner(0.1)

    this.yStackedAxisScale = d3.scaleLinear()
      .domain([0, d3.max(this.series, d => d3.max(d, d => d[1]))])
      .nice()
      .rangeRound([this.innerHeight, 0])

    this.yGroupedAxisScale = d3.scaleLinear()
      .domain([0, d3.max(this.data, d => d3.max(this.keys, key => +d[key]))])
      .nice()
      .rangeRound([this.innerHeight, 0])

    this.colorScale = d3.scaleSequential(this.color)
      .domain([-0.5 * this.keys.length, 1.5 * this.keys.length])
  }

  /**
   * @description: 更新X轴 
   * @param {type} 
   * @return {type} 
   */
  renderXAxes() {
    this.xAxis = this.xAxisGroup.transition()
      .call(d3.axisBottom(this.xAxisScale))
  }

  /**
   * @description: 更新Y轴 
   * @param {type} 
   * @return {type} 
   */
  renderYStackedAxes() {
    this.yStackedAxis = this.yAxisGroup
      .transition()
      .duration(1000)
      .call(d3.axisLeft(this.yStackedAxisScale).ticks(null, 's'));
  }

  /**
   * @description: 更新Y轴 
   * @param {type} 
   * @return {type} 
   */
  renderYGroupedAxes() {
    this.yGroupedAxis = this.yAxisGroup
      .transition()
      .duration(1000)
      .call(d3.axisLeft(this.yGroupedAxisScale).ticks(null, 's'));
  }

  /**
   * @description: 绘制柱状图
   * @param {type} 
   * @return {type} 
   */
  renderRects() {
    this.rects = this.rectsGroup.selectAll("g")
      .data(this.series)
      .join("g")
      .attr("fill", (d, i) => this.colorScale(i))
      .selectAll("rect")
      .data(d => d)
      .join("rect")
      .attr("height", d => this.yStackedAxisScale(d[0]) - this.yStackedAxisScale(d[1]))
      .attr("width", this.xAxisScale.bandwidth())
      .attr("x", (d, i) => this.xAxisScale(d.data[this.groupKey]))
      .attr("y", d => this.yStackedAxisScale(d[1]))
  }

  transitionGrouped() {
    this.renderYGroupedAxes();
    this.rects.transition()
      .duration(500)
      .delay((d, i) => i * 20)
      .attr("x", d => this.xAxisScale(d.data[this.groupKey]) + this.xAxisScale.bandwidth() / this.keys.length * d.index)
      .attr("width", this.xAxisScale.bandwidth() / this.keys.length)
      .transition()
      .attr("y", d => this.yGroupedAxisScale(d[1] - d[0]))
      .attr("height", d => this.yGroupedAxisScale(0) - this.yGroupedAxisScale(d[1] - d[0]));
  }

  transitionStacked() {
    this.renderYStackedAxes();
    this.rects.transition()
      .duration(500)
      .delay((d, i) => i * 20)
      .attr("y", d => this.yStackedAxisScale(d[1]))
      .attr("height", d => this.yStackedAxisScale(d[0]) - this.yStackedAxisScale(d[1]))
      .transition()
      .attr("x", (d, i) => this.xAxisScale(d.data[this.groupKey]))
      .attr("width", this.xAxisScale.bandwidth());
  }
}